/*
 *  Copyright 2007 Genoworks
 *  
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License. 
 */

package com.genoworks.retriever.client;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.w3c.dom.Document;

public class SearchResult extends BaseResult {

  private int totalNumberOfResults = -1;

  private int totalNumberOfPages = -1;

  private List<SearchResultEntry> entries = new LinkedList<SearchResultEntry>();

  private SearchResultEntry currentDoc = null;

  private LinkedHashMap<String, Facets> facets = new LinkedHashMap<String, Facets>();

  private Facets currentFacets = null;

  private FacetElement currentFacetElement = null;

  private Map<String, Cluster> clusterList = null;

  private String queryKey = null;

  SearchResult( Document d ) {
    /**
     * not for construction outside the
     * retriever.client package.
     */
    super( d );
  }

  void setTotalNumberOfResults( Number total ) {
    if ( total != null ) {
      totalNumberOfResults = total.intValue();
    }
  }

  void setTotalNumberOfPages( Number total ) {
    if ( total != null ) {
      totalNumberOfPages = total.intValue();
    }
  }

  void addEntry( LinkedHashMap<String, String> entry, float score ) {
    synchronized( entries ) {
      entries.add( new SearchResultEntry( entry, score ) );
    }
  }

  public int getTotalNumberOfResults() {
    return totalNumberOfResults;
  }

  public int getTotalNumberOfPages() {
    return totalNumberOfPages;
  }

  public boolean nextDoc() {
    synchronized( entries ) {
      if ( entries.size() == 0 ) {
        return false;
      }
      currentDoc = entries.remove( 0 );
    }
    return true;
  }

  public String getDocFieldText( String fieldName ) {
    if ( currentDoc != null ) {
      return currentDoc.get( fieldName );
    }
    return null;
  }

  public float getDocScore() {
    if ( currentDoc != null ) {
      return currentDoc.getScore();
    }
    return 0.0F;
  }

  public Set<String> docFieldNameSet() {
    if ( currentDoc != null ) {
      return currentDoc.keySetIterator();
    }
    return null;
  }

  void addFacet( String id, String field, String name, int count ) {
    synchronized( facets ) {
      Facets f = facets.get( id );
      if ( f == null ) {
        f = new Facets( field );
        facets.put( id, f );
      }
      f.add( new FacetElement( name, count ) );
    }
  }

  public boolean nextFacets() {
    synchronized( facets ) {
      if ( facets.size() == 0 ) {
        currentFacets = null;
        return false;
      }
      currentFacets = facets.remove( facets.keySet().iterator().next() );
      return true;
    }
  }

  public boolean nextFacetElement() {
    if ( currentFacets == null ) {
      currentFacetElement = null;
      return false;
    }
    currentFacetElement = currentFacets.pop();
    if ( currentFacetElement == null ) {
      return false;
    }
    return true;
  }

  public String getFacetField() {
    if ( currentFacets != null ) {
      return currentFacets.getField();
    }
    return null;
  }

  public String getFacetName() {
    if ( currentFacetElement != null ) {
      return currentFacetElement.getName();
    }
    return null;
  }

  public int getFacetCount() {
    if ( currentFacetElement != null ) {
      return currentFacetElement.getCount();
    }
    return -1;
  }

  public void addCluster( String id, String keyword, int count ) {
    if ( clusterList == null ) {
      clusterList = new HashMap<String, Cluster>();
    }
    clusterList.put( id, new Cluster( keyword, count ) );
  }

  public void setClusterContentList( String id, List<String> contents ) {
    Cluster c = clusterList.get( id );
    if ( c == null ) {
      return;
    }
    c.contentList = contents;
  }

  public List<Cluster> getClusterList() {
    List<Cluster> result = new LinkedList<Cluster>();
    result.addAll( clusterList.values() );
    return result;
  }

  public class Cluster {

    private String text = null;

    private int count = 0;

    private List<String> contentList = null;

    Cluster( String word, int c ) {
      text = word;
      count = c;
    }

    void setText( String text ) {
      this.text = text;
    }

    public String getText() {
      return text;
    }

    void setCount( int count ) {
      this.count = count;
    }

    public int getCount() {
      return count;
    }

    void setContentList( List<String> keywords ) {
      this.contentList = keywords;
    }

    public List<String> getContentList() {
      return this.contentList;
    }

    public String toString() {
      return "{" + text + ":" + count + "," + contentList + "}";
    }
  }

  private class Facets implements Comparable<Facets> {

    private String field = null;

    private List<FacetElement> elements = new LinkedList<FacetElement>();

    private Facets( String f ) {
      field = f;
    }

    private String getField() {
      return field;
    }

    private void add( FacetElement fe ) {
      synchronized( elements ) {
        elements.add( fe );
      }
    }

    private FacetElement pop() {
      synchronized( elements ) {
        if ( elements.size() > 0 ) {
          return elements.remove( 0 );
        }
        return null;
      }
    }

    public String toString() {
      return "Facets{field=" + field + "}";
    }

    public int compareTo( Facets arg0 ) {
      return field.compareTo( arg0.field );
    }
  }

  private class FacetElement {

    private String name = null;

    private int count = 0;

    private FacetElement( String n, int c ) {
      name = n;
      count = c;
    }

    private String getName() {
      return name;
    }

    private int getCount() {
      return count;
    }

    public String toString() {
      return "FacetElement{name=" + name + ",count=" + count + "}";
    }
  }

  public String getQueryKey() {
    return queryKey;
  }

  void setQueryKey( String key ) {
    this.queryKey = key;
  }
}

class SearchResultEntry {

  private LinkedHashMap<String, String> fields = null;

  private float score = 0.0F;

  SearchResultEntry( LinkedHashMap<String, String> fs, float sc ) {
    fields = fs;
    score = sc;
  }

  String get( String fieldName ) {
    return fields.get( fieldName );
  }

  Set<String> keySetIterator() {
    return fields.keySet();
  }

  float getScore() {
    return score;
  }
}